#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cassert>
using namespace std;

void printsig(sigset_t &pending)
{
    cout << "pendng bitmap: ";
    for (int i = 31; i >= 1; i--)
    {
        if (sigismember(&pending, i))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

/*int main()
{
    sigset_t block, oldblock;
    sigemptyset(&block);
    sigemptyset(&oldblock);
    sigaddset(&block, 2);
    // 屏蔽2号信号(SIGINT)
    int n = sigprocmask(SIG_SETMASK, &block, &oldblock);
    assert(n == 0);//assert()函数在debug模式下有效,release模式去掉该语句,若n后面未被使用,编译器会告警
    cout << "block 2 signal success!" << endl;
    cout << "process pid: "<<getpid() << endl;
    // 给当前进程发送2号信号(命令行操作),由于屏蔽2号信号,2号信号会处于信号未决状态

    while (true)
    {
        // 获取当前进程的pending位图
        sigset_t pending;
        //pending作用是将内核层的未决信号集覆盖式写入pending,此处是否使用sigemptyset()进行比特位全部置0没有影响
        sigemptyset(&pending);
        n = sigpending(&pending);
        assert(n == 0);
        // 打印pending位图中的所有信号
        printsig(pending);
        sleep(2);
    }

    return 0;
}
*/

// 是否会产生金刚不坏的进程,谁都干不掉?
// 9号信号(SIGKILL),19号信号(SIGSTOP)无法被屏蔽,18信号(SIGCONT)会解除对特定信号的屏蔽
/*int main()
{
    sigset_t block, oldblock;
    sigemptyset(&block);
    sigemptyset(&oldblock);
    //屏蔽所有信号:方式1
    //sigfillset(&block);

    //屏蔽所有信号:方式2
    for(int signum=1;signum<=31;signum++)
    {
        sigaddset(&block, signum);
    }
    //屏蔽所有信号,即阻塞信号集全部设置为1(开始设置内核层阻塞信号集)
    int n = sigprocmask(SIG_SETMASK, &block, &oldblock);
    assert(n == 0);
    cout << "block all signal success!" << endl;
    cout << "process pid: "<<getpid() << endl;

    // 给当前进程发送所有信号(命令行操作),由于屏蔽所有信号,所有信号会保存于pending位图中(除非某些信号根本没法屏蔽)

    while (true)
    {
        // 获取当前进程的pending位图
        sigset_t pending;
        //
        sigemptyset(&pending);
        n = sigpending(&pending);
        assert(n == 0);
        // 打印pending位图中的所有信号
        printsig(pending);
        sleep(2);
    }
    return 0;
}
*/

// 解除对2号信号的阻塞&&使用自定义捕捉观察信号递达
// 定义一个计数器count,当计数器累加到20时,解除屏蔽
void handler(int signum)
{
    sigset_t pending;
    sigemptyset(&pending);
    int n = sigpending(&pending);
    assert(n == 0);
    // 打印pending位图中的所有信号
    printsig(pending);
    cout << signum << "号信号被递达处理!" << endl;
}
int main()
{
    // 自定义捕捉2号信号
    signal(SIGINT, handler);

    sigset_t block, oldblock;
    sigemptyset(&block);
    sigemptyset(&oldblock);
    sigaddset(&block, 2);
    // 屏蔽2号信号(SIGINT)
    int n = sigprocmask(SIG_SETMASK, &block, &oldblock);
    assert(n == 0); // assert()函数在debug模式下有效,release模式去掉该语句,若n后面未被使用,编译器会告警
    cout << "block 2 signal success!" << endl;
    cout << "process pid: " << getpid() << endl;
    // 给当前进程发送2号信号(命令行操作),由于屏蔽2号信号,2号信号会处于信号未决状态

    int count = 0;
    while (true)
    {
        // 获取当前进程的pending位图
        sigset_t pending;
        // pending作用是将内核层的未决信号集覆盖式写入pending,此处是否使用sigemptyset()进行比特位全部置0没有影响
        sigemptyset(&pending);
        n = sigpending(&pending);
        assert(n == 0);
        // 打印pending位图中的所有信号
        printsig(pending);
        count++;
        // 解除对2号信号的屏蔽
        if (count == 20)
        {
            cout << "解除对SIGINT信号的屏蔽" << endl;
            n = sigprocmask(SIG_UNBLOCK, &block, &oldblock); // 2号信号会被立即递达,2号信号的默认处理动作为终止进程
            assert(n == 0);
        }
        sleep(2);
    }

    return 0;
}
